package compoundDB.gui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.TableModel;

/**
 * A dialog that takes a list of property names and allows the user to create a new compound or
 * A dialog that takes a list of properties and a list of property names and allows the user to edit a existing compound
 * @author Michael
 */
@SuppressWarnings("serial")
public class DialogAdd extends JDialog implements NamesTableHolder
{

    private static final int dialogWidth = 300;
    private static final int dialogHieght = 400;
    private static final int buttonWidth = 90;
    private static final int buttonHeight = 20;
    private static final Dimension buttonDim = new Dimension(buttonWidth, buttonHeight);
    private ArrayList<ActionListener> observers;
    private JTable tableProperties;
    private JTable tableNames;
    private JScrollPane scrollPaneNames;

    /**
     * Adds a listnener to listen for when the dialog is done creating this compound
     * @param listener the actionListener to be called
     */
    public void addActionListener(ActionListener listener)
    {
        observers.add(listener);
    }

    /**
     * Activates all listeners to tell them that this has got something for it
     */
    private void action()
    {
        for (ActionListener actln : observers) {
            actln.actionPerformed(new ActionEvent(this, 1, ""));
        }
    }

    @Override
    public void dispose()
    {
        super.dispose();
    }

    /**
     * Returns the names of the new compound
     * @return the array of names
     */
    public String[] getArrayNames()
    {
        NamesTableModel model = (NamesTableModel) tableNames.getModel();
        return model.dumpToArray();
    }

    /**
     * Returns the properties of the new compound
     * @return the array of properties
     */
    public Object[] getArrayProperties()
    {
        TableModel model = tableProperties.getModel();
        Object[] comp = new Object[model.getRowCount() + 1];
        comp[0] = Boolean.valueOf(false);
        for (int i = 1; i < comp.length; i++) {
            comp[i] = model.getValueAt(i - 1, 1);
        }

        return comp;
    }

    /**
     * Creates but not shows the new add compound dialog box (see other constructor for edit compound)
     * @param title the name of the dialog box, something like add new compound
     * @param props the list of possible properties
     */
    public DialogAdd(String title, String[] props)
    {
        setUpWindow(title);

        JPanel contentPanel = new JPanel();
        contentPanel.setLayout(new BorderLayout());
        contentPanel.add(createConstant(), BorderLayout.NORTH);
        contentPanel.add(setUpTableProperties(createFullArray(props)), BorderLayout.CENTER);
        contentPanel.add(setUpTableNames(new String[0]), BorderLayout.SOUTH);
        add(contentPanel);
    }

    /**
     * Creates but not shows the new edit compound dialog box (see other constructor for add compound)
     * @param title the name of the dialog box, something like edit existing compound
     * @param props the list of possible properties
     * @param data the properties from the existing compound
     * @param names the names from the existing compound
     */
    public DialogAdd(String title, String[] props, Object[] data, String[] names)
    {
        setUpWindow(title);
        if (names == null) {
            names = new String[0];
        }
        JPanel contentPanel = new JPanel();
        contentPanel.setLayout(new BorderLayout());
        contentPanel.add(createConstant(), BorderLayout.NORTH);
        contentPanel.add(setUpTableProperties(mergeFullArray(props, data)));
        contentPanel.add(setUpTableNames(names), BorderLayout.SOUTH);
        add(contentPanel);
    }

    /**
     * sets up a JTable from the data given (for add new compounds)
     * @param data the data for the table in strings
     * @return the Scroll pane with the table in it
     */
    private JScrollPane setUpTableNames(String[] data)
    {
        tableNames = new JTable(new NamesTableModel(data, this, true));
        scrollPaneNames = new JScrollPane(tableNames);
        scrollPaneNames.setPreferredSize(new Dimension(dialogWidth - buttonHeight, (2 + tableNames.getModel().getRowCount()) * tableNames.getRowHeight()));

        return scrollPaneNames;
    }

    @Override
    public void refreshNamesHeight()
    {
        if (tableNames.getModel().getRowCount() < 8) {
            scrollPaneNames.setPreferredSize(new Dimension(dialogWidth - buttonHeight, (2 + tableNames.getModel().getRowCount()) * tableNames.getRowHeight()));
        } else {
            scrollPaneNames.setPreferredSize(new Dimension(dialogWidth - buttonHeight, (10) * tableNames.getRowHeight()));
        }
        Object temp = this.getContentPane();
        temp = ((Container) temp).getComponent(0);
        ((JPanel) temp).updateUI();
    }

    /**
     * sets up a JTable from the data given (for edit existing compounds)
     * @param data the data for the table in Objects
     * @return the Scroll pane with the table in it
     */
    private JScrollPane setUpTableProperties(Object[][] data)
    {
        tableProperties = new JTable(new PreviewTableModel(new String[]{"Property", "Value"}, data, true));
        JScrollPane scrolPane = new JScrollPane(tableProperties);

        return scrolPane;
    }

    /**
     * initalizes the basic dialog stuff
     * @param title the title of the dialog
     */
    private void setUpWindow(String title)
    {
        this.setModal(true);
        setSize(dialogWidth, dialogHieght);
        setTitle(title);
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        Dimension size = getToolkit().getScreenSize();
        setLocation(size.width / 3 * 2 - getWidth() / 2, size.height / 3 - getHeight() / 2);

        this.setAlwaysOnTop(true);
        observers = new ArrayList<ActionListener>();
    }

    /**
     * activates the dialog
     */
    public void go()
    {
        this.setVisible(true);
    }

    /**
     * merges the 2 arrays to create a table for edit existing
     * @param props array column 1
     * @param start array column 2
     * @return the full array
     */
    private static Object[][] mergeFullArray(String[] props, Object[] start)
    {
        if (start.length != props.length) {
            throw new IllegalArgumentException();
        }
        Object[][] comp = new Object[props.length - 1][2];
        for (int i = 1; i < props.length; i++) {
            comp[i - 1][0] = props[i];
            comp[i - 1][1] = start[i];
        }
        return comp;
    }

    /**
     * merges a array with a blank column to create a table for add new
     * @param array column 1
     * @return the full array
     */
    private static Object[][] createFullArray(String[] props)
    {
        Object[][] comp = new Object[props.length - 1][2];
        for (int i = 1; i < props.length; i++) {
            comp[i - 1][0] = props[i];
            comp[i - 1][1] = "";
        }
        comp[0][1] = "Given by database";
        comp[1][1] = "Given by database";
        return comp;
    }

    /**
     * Creates the buttons for the dialog (same for both types)
     * @return the panel with the buttons on it
     */
    public JPanel createConstant()
    {
        JPanel pan = new JPanel();

        JButton butAccept = new JButton("Confirm");
        butAccept.setToolTipText("Adds a compound to the database");
        butAccept.setPreferredSize(buttonDim);
        butAccept.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(ActionEvent event)
            {
                action();
            }
        });

        JButton butCancel = new JButton("Cancel");
        butCancel.setToolTipText("Adds a compound to the database");
        butCancel.setPreferredSize(buttonDim);
        butCancel.addActionListener(new ActionListener()
        {

            @Override
            public void actionPerformed(
                    ActionEvent event)
            {
                dispose();
            }
        });

        pan.add(Box.createHorizontalGlue());
        pan.add(butAccept);
        pan.add(Box.createHorizontalGlue());
        pan.add(butCancel);
        pan.add(Box.createHorizontalGlue());

        return pan;

    }
}
